﻿using IOP.SgrA;
using IOP.SgrA.GLSL;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Numerics;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;

namespace VkSample1214
{
    public class ParticleSystem : IRenderComponent
    {
        /// <summary>
        /// 存放顶点数据的列表
        /// </summary>
        public float[] Points { get; set; }
        /// <summary>
        /// 粒子系统生成粒子的起始x 坐标
        /// </summary>
        public float SX {  get; set; }
        /// <summary>
        /// 粒子系统生成粒子的起始y 坐标
        /// </summary>
        public float SY { get; set; }
        /// <summary>
        /// 粒子系统生成粒子的起始z 跨度
        /// </summary>
        public float XRange {  get; set; }
        /// <summary>
        /// 粒子系统生成粒子的起始y 跨度
        /// </summary>
        public float YRange { get; set; }
        /// <summary>
        /// 每一个粒子的半径
        /// </summary>
        public float HalfSize {  get; set; }
        /// <summary>
        /// 每帧发射的组数
        /// </summary>
        public int GroupCount {  get; set; }
        /// <summary>
        /// 每个粒子的生命期步进
        /// </summary>
        public float LifeSpanStep { get; set; }
        /// <summary>
        /// 每个粒子的最大生命期
        /// </summary>
        public float MaxLifeSpan {  get; set; }
        /// <summary>
        /// 粒子Y 方向速度
        /// </summary>
        public float VY {  get; set; }
        /// <summary>
        /// 粒子Y 轴旋转角度（设置朝向时使用）
        /// </summary>
        public float YAngle {  get; set; }
        /// <summary>
        /// 粒子系统位置x 坐标
        /// </summary>
        public float PositionX {  get; set; }
        /// <summary>
        /// 粒子系统位置z 坐标
        /// </summary>
        public float PositionZ {  get; set; }
        /// <summary>
        /// 粒子系统当前的ID
        /// </summary>
        public int Id {  get; set; }
        public Vector4 StartColor { get; set; }
        public Vector4 EndColor { get; set; }

        public float Radis {  get; set; }
        /// <summary>
        /// 粒子系统的激活批次索引
        /// </summary>
        public int CountIndex {  get; set; }
        public uint VCount { get; set; }
        public int ParticleCount {  get; set; }

        public string Name => nameof(ParticleSystem);

        private Random random = new Random();

        public ParticleSystem(int count, float x, float z, int idIn)
        {
            SX = 0;//初始化粒子系统生成粒子的起始x 坐标
            SY = 0;//初始化粒子系统生成粒子的起始y 坐标
            XRange = X_RANGE[idIn];//初始化粒子系统生成粒子的x 跨度
            YRange = Y_RANGE[idIn];//初始化粒子系统生成粒子的y 跨度
            HalfSize = RADIS[idIn];//初始化粒子半径
            GroupCount = GROUP_COUNT[idIn];//初始化组数
            LifeSpanStep = LIFE_SPAN_STEP[idIn];//初始化声明周期
            Points = InitPoints(count).ToArray();
            MaxLifeSpan = MAX_LIFE_SPAN[idIn];//初始化最大生命周期
            VY = V_Y[idIn];//初始化当前Y方向的速度
            YAngle = 0;//初始化Y方向速度
            PositionX = x;//初始化当前x位置
            PositionZ = z;//初始化当前y位置
            Id = idIn;//初始化当前id
            CountIndex = 1;//初始化辅助索引
            ParticleCount = count;
            StartColor = START_COLOR[idIn];
            EndColor = END_COLOR[idIn];
            Radis = RADIS[idIn] + idIn;
        }

        public List<float> InitPoints(int zcount)
        {
            VCount = (uint)(zcount * 6);
            List<float> points = new List<float>();
            for (int i = 0; i < zcount; i++)
            {
                float px = (float)(SX + XRange * random.NextSingle() - XRange / 2); //计算粒子位置x坐标
                float py = (float)(SY + YRange * random.NextSingle() - YRange / 2);
                float vx = (SX - px) / 150;//计算粒子的x 方向的运动速度
                points.Add(px - HalfSize / 2);//粒子对应的第一个点的x 坐标
                points.Add(py + HalfSize / 2);//粒子对应的第一个点的y 坐标
                points.Add(vx);//粒子对应的第一个点的x 方向运动速度
                points.Add(10.0f);//粒子对应的第一个点的当前生命期——10 代表粒子处于未激活状态
                points.Add(0.0f);
                points.Add(0.0f);
                //其余6个顶点的坐标
                points.Add(px - HalfSize / 2);
                points.Add(py - HalfSize / 2);
                points.Add(vx);
                points.Add(10.0f);
                points.Add(0.0f);
                points.Add(1.0f);

                points.Add(px + HalfSize / 2);
                points.Add(py + HalfSize / 2);
                points.Add(vx);
                points.Add(10.0f);
                points.Add(1.0f);
                points.Add(0.0f);

                points.Add(px + HalfSize / 2);
                points.Add(py + HalfSize / 2);
                points.Add(vx);
                points.Add(10.0f);
                points.Add(1.0f);
                points.Add(0.0f);

                points.Add(px - HalfSize / 2);
                points.Add(py - HalfSize / 2);
                points.Add(vx);
                points.Add(10.0f);
                points.Add(0.0f);
                points.Add(1.0f);

                points.Add(px + HalfSize / 2);
                points.Add(py - HalfSize / 2);
                points.Add(vx);
                points.Add(10.0f);
                points.Add(1.0f);
                points.Add(1.0f);
            }

            for (int j = 0; j < GroupCount; j++)
            {
                points[6 * j * 6 + 3] = LifeSpanStep;//设置粒子第1 个点的生命期，不为10 表示粒子处于活跃状态
                points[6 * j * 6 + 9] = LifeSpanStep;//设置粒子第2 个点的生命期，不为10 表示粒子处于活跃状态
                points[6 * j * 6 + 15] = LifeSpanStep;//设置粒子第3 个点的生命期，不为10 表示粒子处于活跃状态
                points[6 * j * 6 + 21] = LifeSpanStep;//设置粒子第4 个点的生命期，不为10 表示粒子处于活跃状态
                points[6 * j * 6 + 27] = LifeSpanStep;//设置粒子第5 个点的生命期，不为10 表示粒子处于活跃状态
                points[6 * j * 6 + 33] = LifeSpanStep;//设置粒子第6 个点的生命期，不为10 表示粒子处于活跃状态
            }

            return points;
        }

        public void Update(Vector3 cameraPos)
        {
            if (CountIndex >= ParticleCount / GroupCount) CountIndex = 0;
            for (int i = 0; i < ParticleCount; i++)
            {
                if (Points[i * 6 * 6 + 3] != 10)
                {
                    Points[i * 6 * 6 + 3] += LifeSpanStep;//计算当前生命周期
                    Points[i * 6 * 6 + 9] += LifeSpanStep;
                    Points[i * 6 * 6 + 15] += LifeSpanStep;
                    Points[i * 6 * 6 + 21] += LifeSpanStep;
                    Points[i * 6 * 6 + 27] += LifeSpanStep;
                    Points[i * 6 * 6 + 33] += LifeSpanStep;
                    if (Points[i * 6 * 6 + 3] > MaxLifeSpan)//当前生命期大于最大生命期时
                    {
                        float px = (float)(SX + XRange * random.NextSingle() - XRange / 2);//计算下一轮的x 坐标
                        float py = (float)(SY + YRange * random.NextSingle() - YRange / 2);//计算下一轮的y 坐标
                        float vx = (SX - px) / 150.0f;//计算粒子下一轮x 方向的速度
                        Points[i * 6 * 6] = px - HalfSize / 2;//粒子对应的第一个顶点的x 坐标
                        Points[i * 6 * 6 + 1] = py + HalfSize / 2;//粒子对应的第一个顶点的y 坐标
                        Points[i * 6 * 6 + 2] = vx;//粒子对应的第一个顶点的x 方向的运动速度
                        Points[i * 6 * 6 + 3] = 10.0f;//粒子对应的第一个顶点的当前生命期
                        Points[i * 6 * 6 + 6] = px - HalfSize / 2;
                        Points[i * 6 * 6 + 7] = py - HalfSize / 2;
                        Points[i * 6 * 6 + 8] = vx;
                        Points[i * 6 * 6 + 9] = 10.0f;
                        Points[i * 6 * 6 + 12] = px + HalfSize / 2;
                        Points[i * 6 * 6 + 13] = py + HalfSize / 2;
                        Points[i * 6 * 6 + 14] = vx;
                        Points[i * 6 * 6 + 15] = 10.0f;
                        Points[i * 6 * 6 + 18] = px + HalfSize / 2;
                        Points[i * 6 * 6 + 19] = py + HalfSize / 2;
                        Points[i * 6 * 6 + 20] = vx;
                        Points[i * 6 * 6 + 21] = 10.0f;
                        Points[i * 6 * 6 + 24] = px - HalfSize / 2;
                        Points[i * 6 * 6 + 25] = py - HalfSize / 2;
                        Points[i * 6 * 6 + 26] = vx;
                        Points[i * 6 * 6 + 27] = 10.0f;
                        Points[i * 6 * 6 + 30] = px + HalfSize / 2;
                        Points[i * 6 * 6 + 31] = py - HalfSize / 2;
                        Points[i * 6 * 6 + 32] = vx;
                        Points[i * 6 * 6 + 33] = 10.0f;
                    }
                    else
                    {
                        Points[i * 6 * 6] += Points[i * 6 * 6 + 2];//计算粒子对应的第一个顶点的x 坐标
                        Points[i * 6 * 6 + 1] += VY;//计算粒子对应的第一个顶点的y 坐标
                        Points[i * 6 * 6 + 6] += Points[i * 6 * 6 + 8];
                        Points[i * 6 * 6 + 7] += VY;
                        Points[i * 6 * 6 + 12] += Points[i * 6 * 6 + 14];
                        Points[i * 6 * 6 + 13] += VY;
                        Points[i * 6 * 6 + 18] += Points[i * 6 * 6 + 20];
                        Points[i * 6 * 6 + 19] += VY;
                        Points[i * 6 * 6 + 24] += Points[i * 6 * 6 + 26];
                        Points[i * 6 * 6 + 25] += VY;
                        Points[i * 6 * 6 + 30] += Points[i * 6 * 6 + 32];
                        Points[i * 6 * 6 + 31] += VY;
                    }
                }
            }
            for (int i = 0; i < GroupCount; i++)
            {
                if (Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 3] == 10)
                {
                    Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 3] = LifeSpanStep;//激活对应的粒子
                    Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 9] = LifeSpanStep;//激活对应的粒子
                    Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 15] = LifeSpanStep;//激活对应的粒子
                    Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 21] = LifeSpanStep;//激活对应的粒子
                    Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 27] = LifeSpanStep;//激活对应的粒子
                    Points[GroupCount * CountIndex * 6 * 6 + 6 * i * 6 + 33] = LifeSpanStep;//激活对应的粒子
                }
            }
            CountIndex++;
            CalculateBillboardDirection(cameraPos);
        }

        public void CalculateBillboardDirection(Vector3 cameraPos)
        {
            float xspan = PositionX - cameraPos.X;
            float zspan = PositionZ - cameraPos.Z;
            if (zspan <= 0)
            {
                YAngle = MathF.Atan(xspan / zspan);
            }
            else
            {
                YAngle = MathF.PI + MathF.Atan(xspan / zspan);
            }
        }

        float ToDegrees(float radian)
        {
            return radian * 180.0f / MathF.PI;
        }

        public void Destroy()
        {
            Points = null;
        }

        public void CloneToNewRender(IRenderObject newObj)
        {
            ParticleSystem newSystem = new ParticleSystem(ParticleCount, PositionX, PositionZ, Id);
            newObj.AddComponent(newSystem);
        }

        public static float[] X_RANGE = { 1.0f, 1.0f, 1.0f, 1.0f };
        public static float[] Y_RANGE = { 0.3f, 0.3f, 0.15f, 0.15f };
        public static float[] RADIS = { 0.8f, 0.8f, 0.8f, 0.8f };
        public static int[] COUNT = { 340, 340, 99, 99 };
        public static int[] GROUP_COUNT = { 4, 4, 1, 1 };
        public static float[] LIFE_SPAN_STEP = { 0.07f, 0.07f, 0.07f, 0.07f };
        public static float[] MAX_LIFE_SPAN = { 5.0f, 5.0f, 6.0f, 6.0f };
        public static float[] V_Y = { 0.05f, 0.05f, 0.04f, 0.04f };
        public static float[][] ParticlePositon = { 
            [7.0f,7.0f], [-7.0f,-7.0f], 
            [-7.0f,7.0f], [7.0f,-7.0f],
        };
        public static Vector4[] START_COLOR = { 
            new Vector4(0.7569f,0.2471f,0.1176f,1.0f), new Vector4(0.7569f,0.2471f,0.1176f,1.0f), 
            new Vector4(0.6f,0.6f,0.6f,1.0f), new Vector4(0.6f,0.6f,0.6f,1.0f),
        };
        public static Vector4[] END_COLOR = { 
            Vector4.Zero, Vector4.Zero,
            Vector4.Zero, Vector4.Zero,
        };
    }

}
